
//#if OPENGL
//#if MONOMAC
//using MonoMac.OpenGL;
//#elif WINDOWS || LINUX
//using OpenTK.Graphics.OpenGL;
//#elif GLES
//using OpenTK.Graphics.ES20;
//using PixelInternalFormat = OpenTK.Graphics.ES20.All;
//using PixelFormat = OpenTK.Graphics.ES20.All;
//using PixelType = OpenTK.Graphics.ES20.All;
//using TextureTarget = OpenTK.Graphics.ES20.All;
//using TextureParameterName = OpenTK.Graphics.ES20.All;
//using TextureMinFilter = OpenTK.Graphics.ES20.All;
//#endif
//#elif DIRECTX
//using SharpDX;
//using SharpDX.Direct3D11;
//#elif PSM
//using Sce.PlayStation.Core.Graphics;
//#endif

#ifndef TextureCube_h
#define TextureCube_h

#include <Defines.h>
#include <CSharpPropertyMethods.h>

#include <System/RObject.h>
#include <System/RNullable.h>
#include <System/IDisposable.h>
#include <System/RNotImplementedException.h>
#include <System/RArgumentNullException.h>
#include <System/RMath.h>
#include <System/IO/RStream.h>

#include "GraphicsResource.h"
//#include "GraphicsDevice.h"
#include "SurfaceFormat.h"
#include "Texture.h"
#include "../Rectangle.h"
#include <Riccsson/Xna/Framework/Graphics/CubeMapFace.h>

namespace Riccsson
{
	namespace Xna
	{
		namespace Framework
		{
			namespace Graphics
			{
				class TextureCube : public Texture
				{
					protected: int size;

					/// <summary>
					/// Gets the width and height of the cube map face in pixels.
					/// </summary>
					/// <value>The width and height of a cube map face in pixels.</value>
					public: PROP3_GET(int, Size)
					{
						return size;
					}
		
			//#if DIRECTX
			//
			//#elif PSM
			//		//TODO
			//#else
			//		PixelInternalFormat glInternalFormat;
			//		PixelFormat glFormat;
			//		PixelType glType;
			//#endif
		
					public: TextureCube (GraphicsDevice* graphicsDevice, int size, bool mipMap, SurfaceFormat format)
					{
						init(graphicsDevice, size, mipMap, format, false);
					}

					private: /*internal*/ TextureCube(GraphicsDevice* graphicsDevice, int size, bool mipMap, SurfaceFormat format, bool renderTarget)
					{
						init(graphicsDevice, size, mipMap, format, renderTarget);
					}

					private: void init(GraphicsDevice* graphicsDevice, int size, bool mipMap, SurfaceFormat format, bool renderTarget)
					{
						if (graphicsDevice == null)
							throw Riccsson::System::ArgumentNullException("graphicsDevice");
			
						this->graphicsDevice = graphicsDevice;
						this->size = size;
						this->format = format;
						this->levelCount = mipMap ? CalculateMipLevels(size) : 1;

			//#if DIRECTX
			//			var description = new Texture2DDescription
			//			{
			//				Width = size,
			//				Height = size,
			//				MipLevels = levelCount,
			//				ArraySize = 6, // A texture cube is a 2D texture array with 6 textures.
			//				Format = SharpDXHelper.ToFormat(format),
			//				BindFlags = BindFlags.ShaderResource,
			//				CpuAccessFlags = CpuAccessFlags.None,
			//				SampleDescription = { Count = 1, Quality = 0 },
			//				Usage = ResourceUsage.Default,
			//				OptionFlags = ResourceOptionFlags.TextureCube
			//			};
			//
			//			if (renderTarget)
			//			{
			//				description.BindFlags |= BindFlags.RenderTarget;
			//				if (mipMap)
			//					description.OptionFlags |= ResourceOptionFlags.GenerateMipMaps;
			//			}
			//
			//			_texture = new SharpDX.Direct3D11.Texture2D(graphicsDevice._d3dDevice, description);
			//#elif PSM
			//			//TODO
			//#else
			//			this->glTarget = TextureTarget::TextureCubeMap;
			//#if IOS || ANDROID
			//			GL.GenTextures(1, this->glTexture);
			//#else
			//			GL.GenTextures(1, this->glTexture);
			//#endif
			//			GraphicsExtensions.CheckGLError();
			//			GL.BindTexture(TextureTarget::TextureCubeMap, this->glTexture);
			//			GraphicsExtensions.CheckGLError();
			//			GL.TexParameter(TextureTarget::TextureCubeMap, TextureParameterName.TextureMinFilter,
			//							mipMap ? (int)TextureMinFilter.LinearMipmapLinear : (int)TextureMinFilter.Linear);
			//			GraphicsExtensions.CheckGLError();
			//			GL.TexParameter(TextureTarget::TextureCubeMap, TextureParameterName.TextureMagFilter,
			//							(int)TextureMagFilter.Linear);
			//			GraphicsExtensions.CheckGLError();
			//			GL.TexParameter(TextureTarget::TextureCubeMap, TextureParameterName.TextureWrapS,
			//							(int)TextureWrapMode.ClampToEdge);
			//			GraphicsExtensions.CheckGLError();
			//			GL.TexParameter(TextureTarget::TextureCubeMap, TextureParameterName.TextureWrapT,
			//							(int)TextureWrapMode.ClampToEdge);
			//			GraphicsExtensions.CheckGLError();
			//
			//
			//			format.GetGLFormat(glInternalFormat, glFormat, glType);
			//
			//			for (int i=0; i<6; i++) 
			//			{
			//				TextureTarget* target = GetGLCubeFace((CubeMapFace)i);
			//
			//				if (glFormat == (PixelFormat)All.CompressedTextureFormats) 
			//				{
			//					throw Riccsson::System::NotImplementedException();
			//				} 
			//				else 
			//				{
			//#if IOS || ANDROID
			//					GL.TexImage2D (target, 0, (int)glInternalFormat, size, size, 0, glFormat, glType, IntPtr.Zero);
			//#else
			//					GL.TexImage2D (target, 0, glInternalFormat, size, size, 0, glFormat, glType, IntPtr.Zero);
			//#endif
			//					GraphicsExtensions.CheckGLError();
			//				}
			//			}
			//
			//			if (mipMap)
			//			{
			//#if IOS || ANDROID
			//				GL.GenerateMipmap(TextureTarget::TextureCubeMap);
			//#else
			//				GL.TexParameter(TextureTarget::TextureCubeMap, TextureParameterName.GenerateMipmap, (int)All.True);
			//#endif
			//				GraphicsExtensions.CheckGLError();
			//			}
			//#endif
					}

					/// <summary>
					/// Gets a copy of cube texture data specifying a cubemap face.
					/// </summary>
					/// <typeparam name="T"></typeparam>
					/// <param name="cubeMapFace">The cube map face.</param>
					/// <param name="data">The data.</param>
					public: template<struct T> void GetData(CubeMapFace cubeMapFace, Riccsson::System::Array<T>* data)
					{
						//FIXME Does not compile on Android or iOS
			//#if MONOMAC
			//			TextureTarget target = GetGLCubeFace(cubeMapFace);
			//			GL.BindTexture(target, this->glTexture);
			//			// 4 bytes per pixel
			//			if (data.Length < size * size * 4)
			//				throw Riccsson::System::ArgumentException("data");
			//
			//			GL.GetTexImage<T>(target, 0, PixelFormat.Bgra,
			//				PixelType.UnsignedByte, data);
			//#else
			//			throw Riccsson::System::NotImplementedException();
			//#endif
					}

					public: template<struct T> void SetData (CubeMapFace face, Riccsson::System::Array<T>* data)
					{
						SetData(face, 0, null, data, 0, data.Length);
					}

					public: template<struct T> void SetData(CubeMapFace face, Riccsson::System::Array<T>* data, int startIndex, int elementCount)
					{
						SetData(face, 0, null, data, startIndex, elementCount);
					}
		
					public: template<struct T> void SetData(CubeMapFace face, int level, System::Nullable<Rectangle> rect, Riccsson::System::Array<T>* data, int startIndex, int elementCount)
					{
						if (data == null) 
							throw Riccsson::System::ArgumentNullException("data");

						var elementSizeInByte = Marshal.SizeOf(typeof(T));
						var dataHandle = GCHandle.Alloc(data, GCHandleType.Pinned);
						var dataPtr = (IntPtr)(dataHandle.AddrOfPinnedObject().ToInt64() + startIndex * elementSizeInByte);
			
						int xOffset, yOffset, width, height;
						if (rect.HasValue)
						{
							xOffset = rect.Value.X;
							yOffset = rect.Value.Y;
							width = rect.Value.Width;
							height = rect.Value.Height;
						}
						else
						{
							xOffset = 0;
							yOffset = 0;
							width = Math.Max(1, this->size >> level);
							height = Math.Max(1, this->size >> level);

			//#if DIRECTX
			//				// For DXT textures the width and height of each level is a multiply of 4.
			//				if (format == SurfaceFormat.Dxt1 || format == SurfaceFormat.Dxt3 || format == SurfaceFormat.Dxt5)
			//				{
			//					width = ((width + 3) / 4) * 4;
			//					height = ((height + 3) / 4) * 4;
			//				}
			//#endif
						}

			//#if DIRECTX
			//			var box = new DataBox(dataPtr, GetPitch(width), 0);
			//
			//			int subresourceIndex = (int)face * levelCount + level;
			//
			//			var region = new ResourceRegion
			//			{
			//				Top = yOffset,
			//				Front = 0,
			//				Back = 1,
			//				Bottom = yOffset + height,
			//				Left = xOffset,
			//				Right = xOffset + width
			//			};
			//
			//			var d3dContext = GraphicsDevice._d3dContext;
			//			lock (d3dContext)
			//				d3dContext.UpdateSubresource(box, _texture, subresourceIndex, region);
			//#elif PSM
			//			//TODO
			//#else
			//			GL.BindTexture (TextureTarget::TextureCubeMap, this->glTexture);
			//			GraphicsExtensions.CheckGLError();
			//
			//			TextureTarget target = GetGLCubeFace(face);
			//			if (glFormat == (PixelFormat)All.CompressedTextureFormats) 
			//			{
			//				throw Riccsson::System::NotImplementedException();
			//			} 
			//			else 
			//			{
			//				GL.TexSubImage2D(target, level, xOffset, yOffset, width, height, glFormat, glType, dataPtr);
			//				GraphicsExtensions.CheckGLError();
			//			}
			//#endif
						dataHandle.Free ();
					}
		
			//#if OPENGL
			//		private TextureTarget GetGLCubeFace(CubeMapFace face) 
			//		{
			//			switch (face) 
			//			{
			//			case CubeMapFace.PositiveX: return TextureTarget::TextureCubeMapPositiveX;
			//			case CubeMapFace.NegativeX: return TextureTarget::TextureCubeMapNegativeX;
			//			case CubeMapFace.PositiveY: return TextureTarget::TextureCubeMapPositiveY;
			//			case CubeMapFace.NegativeY: return TextureTarget::TextureCubeMapNegativeY;
			//			case CubeMapFace.PositiveZ: return TextureTarget::TextureCubeMapPositiveZ;
			//			case CubeMapFace.NegativeZ: return TextureTarget::TextureCubeMapNegativeZ;
			//			}
			//			throw Riccsson::System::ArgumentException();
			//		}
			//#endif

				};
			}
		}
	}
}

#endif